// app_ble.c
#include "app_ble.h"
#include "at_task.h"

static uint16_t adv_len = 0;
static uint8_t adv_data[31] = {
    0x02,AD_TYPE_FLAGS, FLAG_BIT_LE_GENERAL_DISCOVERABLE_MODE|FLAG_BIT_BR_EDR_NOT_SUPPORTED,
	0x08,0x09,'B','l','u','e','N','R','G',
	0x12,0xFF,
};


uint8_t dev_name[MAX_DEV_LEN+1] = {DEF_DEV_NAME};

static uint8_t  advertising = 0;
// 作为从机时的连接句柄
static uint16_t con_handle_S = 0;

static at_obj_t *at_obj;


static master_device masters[1];




extern uint16_t TXCharHandle, RXCharHandle;


void app_ble_init(at_obj_t* obj)
{
  at_obj = obj;
}

// 生成静态MAC地址参考函数
void generate_static_mac_addr(uint8_t bdaddr[6])
{
	// get UID
	BYTE text1[8];
	uint32_t word0 = LL_GetUID_Word0();
	uint32_t word1 = LL_GetUID_Word1();
	memcpy(text1,&word0,sizeof(word0));
	memcpy(&text1[4],&word1,sizeof(word1));
	BYTE buf[SHA256_BLOCK_SIZE];
	SHA256_CTX ctx;
	sha256_init(&ctx);
	sha256_update(&ctx, text1, sizeof(text1));
	sha256_final(&ctx, buf);
	buf[5] |= 0xC0;
	memcpy(bdaddr,buf,6);
}


void enable_adv(uint8_t Enable)
{
	static Advertising_Set_Parameters_t Advertising_Set_Parameters[1];
	Advertising_Set_Parameters[0].Advertising_Handle = 0;
	Advertising_Set_Parameters[0].Duration = 0;
	Advertising_Set_Parameters[0].Max_Extended_Advertising_Events = 0;
	
	uint8_t ret = aci_gap_set_advertising_enable(Enable, 1, Advertising_Set_Parameters); 
	if (ret != BLE_STATUS_SUCCESS)
	  COMPrintf ("Error in aci_gap_set_advertising_enable(): 0x%02x\r\n", ret);
	else{
	  COMPrintf ("aci_gap_set_advertising_enable() --> SUCCESS\r\n");
	  advertising = TRUE;
	}
}



void default_ble_init(void)
{
	uint8_t mac[6];
	uint16_t service_handle;
	uint16_t dev_name_char_handle;
	uint16_t appearance_char_handle;
	generate_static_mac_addr(mac);
	tBleStatus ret = aci_hal_write_config_data(CONFIG_DATA_STATIC_RANDOM_ADDRESS, 6, mac);
	if(ret != BLE_STATUS_SUCCESS){
        COMPrintf("aci_hal_write_config_data:%x \r\n", ret);
	}

    ret = aci_hal_set_tx_power_level(0, 0x19);
	if(ret != BLE_STATUS_SUCCESS){
		COMPrintf("aci_hal_set_tx_power_level:%x \r\n", ret);
	}
	ret = aci_gatt_srv_init();
	if(ret != BLE_STATUS_SUCCESS){
		COMPrintf("aci_gatt_srv_init:%x \r\n", ret);
	}
	
	ret = aci_gap_init(0xff, 0x00, sizeof(dev_name), 0x01, &service_handle, &dev_name_char_handle, &appearance_char_handle);
	if(ret != BLE_STATUS_SUCCESS){
		COMPrintf("aci_gap_init:%x \r\n", ret);
	}
	ret = Gap_profile_set_dev_name(0, strlen((char*)dev_name), dev_name);
	if(ret != BLE_STATUS_SUCCESS){
		COMPrintf("Gap_profile_set_dev_name:%x \r\n", ret);
	}


	ret = Add_SerialPort_Service();
	if(ret != BLE_STATUS_SUCCESS){
		printf("Add_SerialPort_Service:%x \r\n", ret);
	}


	  ret = aci_gap_set_advertising_configuration(0, GAP_MODE_GENERAL_DISCOVERABLE,
                                              ADV_PROP_CONNECTABLE|ADV_PROP_SCANNABLE|ADV_PROP_LEGACY,
                                              100, 100,
                                              ADV_CH_ALL,
                                              0,NULL,
                                              ADV_NO_WHITE_LIST_USE,
                                              0, /* 0 dBm */
                                              LE_1M_PHY, /* Primary advertising PHY */
                                              0, /* 0 skips */
                                              LE_1M_PHY, /* Secondary advertising PHY. Not used with legacy advertising. */
                                              0, /* SID */
                                              0 /* No scan request notifications */);
  COMPrintf("Advertising configuration %02X\n", ret);
  
  static uint8_t manuf_data[] = { 
    0x02,AD_TYPE_FLAGS, FLAG_BIT_LE_GENERAL_DISCOVERABLE_MODE|FLAG_BIT_BR_EDR_NOT_SUPPORTED,
    9,                      /* Length of AD type Complete Local Name */         
    13,                     /* Length of AD type Manufacturer info */
    0xFF,                   /* AD type Manufacturer info */
    0x01,                   /* Protocol version */
    0x05,		      /* Device ID: 0x05 = STEVAL-BCN002V1 Board */
    0x00,                   /* Feature Mask byte#1 */
    0x00,                   /* Feature Mask byte#2 */
    0x00,                   /* Feature Mask byte#3 */
    0x00,                   /* Feature Mask byte#4 */
    0x00,                   /* BLE MAC start */
    0x00, 
    0x00, 
    0x00, 
    0x00, 
    0x00                    /* BLE MAC stop */
  };

  ret = aci_gap_set_advertising_data(0, ADV_COMPLETE_DATA, sizeof(adv_data), adv_data);
  
  COMPrintf("Set advertising data %02X\n", ret); 

  enable_adv(ENABLE);

}





int notify_data_handler(at_urc_info_t *info)
{
    uint16_t pos = CMD_LEN(NOTIFY_DATA)+1;
	uint16_t len = info->urclen - pos -1;

	if(masters[0].conn_handle == 0){
		at_exec_cmd(at_obj, NULL,"AT+%s=Didn't create connectione yet!",enumToStr(NOTIFY_DATA));
        return 0;
	}

	if(len > 0){
      tBleStatus ret  =  aci_gatt_srv_notify(masters[0].conn_handle, TXCharHandle + 1, 0, 
		len, (uint8_t*)(info->urcbuf+pos));
      if(ret == BLE_STATUS_SUCCESS){
        printf("Data sent to master:%d \n", len);
		at_exec_cmd(at_obj, NULL,"AT+%s=OK",enumToStr(NOTIFY_DATA));
      }
      else
        COMPrintf(" failed  to sent \n");
	}
    return 0;
}


void hci_le_enhanced_connection_complete_event(uint8_t Status,
                                               uint16_t Connection_Handle,
                                               uint8_t Role,
                                               uint8_t Peer_Address_Type,
                                               uint8_t Peer_Address[6],
                                               uint8_t Local_Resolvable_Private_Address[6],
                                               uint8_t Peer_Resolvable_Private_Address[6],
                                               uint16_t Conn_Interval,
                                               uint16_t Conn_Latency,
                                               uint16_t Supervision_Timeout,
                                               uint8_t Master_Clock_Accuracy)
{
  uint8_t buffer_out[258];

  if(Status == 0){
  	  masters[0].conn_handle = Connection_Handle;
	  masters[0].address_type = Peer_Address_Type;
      memcpy(masters[0].address, Peer_Address, 6);
	  aci_gatt_clt_exchange_config(Connection_Handle);
      at_exec_cmd(at_obj, NULL, "AT+%s=Con_Handle:%x,Role:%s,MAC:%02X:%02X:%02X:%02X:%02X:%02X",
	  											enumToStr(ONCONNECTED), 
	  											Connection_Handle,
	  											(Role==1?"Master":"Slave"),
	  											Peer_Address[5],Peer_Address[4],Peer_Address[3],
	  											Peer_Address[2],Peer_Address[1],Peer_Address[0]
	  											);
												
  }

}


void hci_disconnection_complete_event(uint8_t Status,
                                      uint16_t Connection_Handle,
                                      uint8_t Reason)
{
	at_exec_cmd(at_obj, NULL, "AT+%s=Con_Handle:%x,Reason:%x",
														enumToStr(ONDISCONNECTED), 
														Connection_Handle,
														Reason
														);
	enable_adv(ENABLE);
}

/**
 * @brief This event is generated to the application by the GATT server when a
 *        client modifies any attribute on the server, as consequence of one of
 *        the following GATT procedures: - write without response - signed write
 *        without response - write characteristic value - write long
 *        characteristic value - reliable write.
 * @param Connection_Handle The connection handle which modified the attribute.
 * @param Attr_Handle Handle of the attribute that was modified.
 * @param Attr_Data_Length Length of Attr_Data in octets
 * @param Attr_Data A concatenation of Handle, Length and Values for each of the
 *        attributes being notified.
 * @retval None
 */
void aci_gatt_srv_attribute_modified_event(uint16_t Connection_Handle,
                                           uint16_t Attr_Handle,
                                           uint16_t Attr_Data_Length,
                                           uint8_t Attr_Data[])
{
  uint8_t buffer_out[532] = {'\0'};


  for(int i=0;i<Attr_Data_Length;i++)
  {
    sprintf((char*)buffer_out+2*i,"%02X", Attr_Data[i]);
  }
	
  at_task_exec_cmd("AT+%s=%s",enumToStr(ATT_MODEFIED),buffer_out);
  
}




void aci_gatt_srv_write_event(uint16_t Connection_Handle,
                              uint8_t Resp_Needed,
                              uint16_t Attribute_Handle,
                              uint16_t Data_Length,
                              uint8_t Data[])
{
  //printf("aci_gatt_srv_write_event\n");
  uint8_t buffer_out[512]={'\0'};
	//ATT_MODEFIED
	for(int i=0;i<Data_Length;i++)
	{
	    sprintf((char*)buffer_out+2*i,"%02X", Data[i]);
	}
	at_task_exec_cmd("AT+%s=%s",enumToStr(GATT_WRITE),buffer_out);

}



